package com.dopplr.examples {

    import com.dopplr.api.API;
    import com.dopplr.api.City;
    import com.dopplr.api.Traveller;
    import com.dopplr.api.Trip;
    
    import flash.display.LoaderInfo;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.ErrorEvent;
    import flash.events.StatusEvent;
    import flash.text.AntiAliasType;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.text.TextFormatAlign;
    import flash.utils.Dictionary;

    [SWF(backgroundColor='#ffffff')]
    public class DopplrSparks extends Sprite
    {
		[Embed(systemFont="Helvetica Neue", fontName="HelveticaNorm", mimeType='application/x-font')]
		public var _helv:String;
		[Embed(systemFont="Helvetica Neue", fontName="HelveticaBold", fontWeight="bold", mimeType='application/x-font')]
		public var _helvbo:String;

        private var api:API;
                
        public function DopplrSparks()
        {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;

            var token:String = LoaderInfo(root.loaderInfo).parameters.token;
            if (token) {    
                api = new API(token);
                api.loadFellowTravellers(onFellowsLoaded);
                api.addEventListener(ErrorEvent.ERROR, onAPIError);
                api.addEventListener(StatusEvent.STATUS, onAPIStatus);
            }
            else {
                var text:TextField = new TextField();
                text.name = 'error';
                text.text = "problem initializing dopplr access: no token found";
                text.width = text.textWidth + 4;
                addChild(text);                
            }            
        }
        
        public function onAPIError(error:ErrorEvent):void
        {
            var text:TextField = this.getChildByName('error') as TextField;
            if (!text) {
                text = new TextField();
                text.name = 'error';
                text.defaultTextFormat = new TextFormat("HelveticaNorm", 10, 0x000000);
                text.embedFonts = true;
                text.antiAliasType = AntiAliasType.ADVANCED;
                text.background = true;
                text.backgroundColor = 0xffff00;
                addChild(text);                
            }
            text.text = error.text;
            text.width = text.textWidth + 4;
        }
        
        public function onAPIStatus(event:StatusEvent):void
        {
            var status:TextField = this.getChildByName('status') as TextField;
            if (!status) {
                status = new TextField();
                status.name = 'status';
                status.defaultTextFormat = new TextFormat("HelveticaNorm", 10, 0x000000);
                status.embedFonts = true;
                status.antiAliasType = AntiAliasType.ADVANCED;
                addChild(status);                
            }
            status.text = event.code;
            status.width = status.textWidth + 4;
            status.height = status.textHeight + 4;
            status.x = stage.stageWidth - status.width - 15;
            status.y = stage.stageHeight - status.height - 15;
        }
        
        public function addCityLabel(city:City, cx:Number, cy:Number):void
        {
            var tf:TextField = new TextField();
            tf.defaultTextFormat = new TextFormat("HelveticaNorm", 8, 0x404040);
            tf.embedFonts = true;
            tf.antiAliasType = AntiAliasType.ADVANCED;
            tf.name = city.geonameId.toString();
            tf.text = city.name + ", " + city.countryCode;
            tf.width = tf.textWidth + 4;
            tf.height = tf.textHeight + 4;
            tf.x = cx;
            tf.y = cy;
            addChild(tf);
        }

        public function onFellowsLoaded(fellows:Array):void
        {
            api.loadFellowTravellersTrips(fellows, drawSomething);
        }
                        
        private function drawSomething(users:Array):void
        {
            var status:TextField = this.getChildByName('status') as TextField;
            if (status) {
                status.visible = false;
            }

            for each (var user:Traveller in api.model.travellers) {
                trace(user.name + " " + user.status + " and has " + user.trips.length + " trip" + (user.trips.length > 1 ? "s" : "") + " that Dopplr knows about");
            }
                        
            trace("there are " + api.model.trips.length + " trips");
            var nowTemp:Date = new Date();
            var now:Date = new Date(Date.UTC(nowTemp.fullYearUTC, nowTemp.monthUTC, nowTemp.dateUTC));
            var millisIn3Months:Number = 90 * 24 * 60 * 60 * 1000;
            var future:Function = function(item:Trip, index:int, array:Array):Boolean
            {
                return item.finish.time > now.time && item.start.time < now.time + millisIn3Months;
            };
            var futureTrips:Array = api.model.trips.filter(future);
            trace("there are " + futureTrips.length + " trips in the future");
            
            var cityDayCounts:Dictionary = new Dictionary();
            var cityMaxCounts:Dictionary = new Dictionary();
            var futureCities:Array = [];
            var millisInDay:Number = 1000 * 60 * 60 * 24;
            var maxDayCount:int = 0;
            var countDays:Function = function(item:Trip, index:int, array:Array):void
            {
                var dayCounts:Dictionary = cityDayCounts[item.city] as Dictionary;
                if (!dayCounts) {
                    dayCounts = new Dictionary();
                    cityDayCounts[item.city] = dayCounts;
                    futureCities.push(item.city);
                }
                var cityMaxCount:int = cityMaxCounts[item.city];
                for (var millis:Number = item.start.time; millis <= item.finish.time; millis += millisInDay) {
                    var day:String = new Date(millis).toUTCString();
                    var count:int = dayCounts[day];
                    if (count) {
                        dayCounts[day] = count + 1;
                        maxDayCount = Math.max(count+1, maxDayCount);
                        cityMaxCount = Math.max(count+1, cityMaxCount);
                    }
                    else {
                        dayCounts[day] = 1;
                        maxDayCount = Math.max(1, maxDayCount);
                        cityMaxCount = 1;
                    }
                }
                cityMaxCounts[item.city] = cityMaxCount;
            };
            futureTrips.forEach(countDays);
            
            var sparkX:Number = 10;
            var sparkY:Number = 10;
            var sparkHeight:Number = 10;
            var sparkPadding:Number = -3;
            var sparkOffsetX:Number = 0;
            var sparkWidth:Number = 100.0;
            var end:Date = new Date(now.time + millisIn3Months);
            futureCities = futureCities.sortOn('dayCount', Array.NUMERIC | Array.DESCENDING);
            for each (var city:City in futureCities) {
                var ellipseX:Number = 0;
                var ellipseY:Number = 0;
                trace(city.name + " spark (max = " + cityMaxCounts[city] + ")");
                var dayCounts:Dictionary = cityDayCounts[city] as Dictionary;
                //graphics.lineStyle(1, city.rgb);
                graphics.lineStyle(1, city.rgb, 1, true);
                graphics.beginFill(0xffffff);
                graphics.moveTo(sparkX, sparkY+sparkHeight);
                for (var millis:Number = now.time; millis <= end.time; millis += millisInDay) {
                    var day:String = new Date(millis).toUTCString();
                    var count:int = dayCounts[day] as int;
                    //trace('\t' + new Date(millis).toDateString() + " " + count);
                    var lineX:Number = sparkX + (sparkWidth * (millis - now.time)/(end.time-now.time));
                    var lineY:Number = sparkY + sparkHeight - (sparkHeight * count / maxDayCount);
                    graphics.lineTo(lineX, lineY);
                }
                graphics.lineStyle();
                graphics.lineTo(sparkX, sparkY+sparkHeight);
                
                addCityLabel(city, sparkX + sparkWidth + 4, sparkY + 3);
                
                sparkY += sparkPadding + sparkHeight;
                sparkX += sparkOffsetX;
                
                if (sparkY >= stage.stageHeight - 10 - sparkHeight) break;
            }
            
            onAPIStatus(new StatusEvent(StatusEvent.STATUS, false, false, "showing 90-day city sparklines for your fellow travellers", "status"));
            
        }
        
    }
    
}

